package com.odin.redis.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;


/**
 * Created by Ice on 2018-11-18.
 */
@Slf4j
@Configuration
public class MyRedisConf {

    /**
     * Redis服务器地址
     */
    @Value("${redis.host}")
    private String host;

    /**
     * Redis服务器连接端口
     */
    @Value("${redis.port}")
    private int port;

    /**
     * Redis服务器连接密码（默认为空）
     */
    @Value("${redis.password}")
    private String password;

    /**
     * 连接超时时间（毫秒）
     */
    @Value("${redis.timeout}")
    private long timeout;

    /**
     * 连接超时时间（毫秒）
     */
    @Value("${redis.database}")
    private int database;

    /**
     * 连接池最大连接数（使用负值表示没有限制）
     */
    @Value("${redis.pool.max-active}")
    private int maxTotal;

    /**
     * 连接池最大阻塞等待时间（使用负值表示没有限制）
     */
    @Value("${redis.pool.max-wait}")
    private int maxWaitMillis;

    /**
     * 连接池中的最大空闲连接
     */
    @Value("${redis.pool.max-idle}")
    private int maxIdle;

    /**
     * 连接池中的最小空闲连接
     */
    @Value("${redis.pool.min-idle}")
    private int minIdle;


    /**
     * 配置JedisPoolConfig
     *
     * @return JedisPoolConfig实体
     */
//    @Bean(name = "jedisPoolConfig")
//    public JedisPoolConfig jedisPoolConfig() {
//        log.info("初始化RedisPoolConfig");
//        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//        // 连接池最大连接数（使用负值表示没有限制）
//        jedisPoolConfig.setMaxTotal(this.maxTotal);
//        // 连接池最大阻塞等待时间（使用负值表示没有限制）
//        jedisPoolConfig.setMaxWaitMillis(this.maxWaitMillis);
//        // 连接池中的最大空闲连接
//        jedisPoolConfig.setMaxIdle(this.maxIdle);
//        // 连接池中的最小空闲连接
//        jedisPoolConfig.setMinIdle(this.minIdle);
////        jedisPoolConfig.setTestOnBorrow(true);
////        jedisPoolConfig.setTestOnCreate(true);
////        jedisPoolConfig.setTestWhileIdle(true);
//        return jedisPoolConfig;
//    }

    /**
     * Lettuce配置信息
     *
     * @param genericObjectPoolConfig
     * @return
     */
    @Bean(name = "lettuceConnectionFactory")
    public LettuceConnectionFactory lettuceConnectionFactory(@Qualifier(value = "myGenericObjectPoolConfig") GenericObjectPoolConfig genericObjectPoolConfig) {
        log.info("----> 初始化LettuceConfig... ");
        // 单机版配置
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setDatabase(database);
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
        // 集群版配置
//        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
//        String[] serverArray = clusterNodes.split(",");
//        Set<RedisNode> nodes = new HashSet<RedisNode>();
//        for (String ipPort : serverArray) {
//            String[] ipAndPort = ipPort.split(":");
//            nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
//        }
//        redisClusterConfiguration.setPassword(RedisPassword.of(password));
//        redisClusterConfiguration.setClusterNodes(nodes);
//        redisClusterConfiguration.setMaxRedirects(maxRedirects);
        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
                .commandTimeout(Duration.ofDays(timeout))
                .poolConfig(genericObjectPoolConfig)
                .build();

        return new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfiguration);
    }

    @Bean(name = "myGenericObjectPoolConfig")
    public GenericObjectPoolConfig genericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();

        genericObjectPoolConfig.setMinIdle(minIdle);
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMaxTotal(maxTotal);
        genericObjectPoolConfig.setMaxWaitMillis(maxWaitMillis);

        return genericObjectPoolConfig;
    }

    /**
     * 实例化 RedisConnectionFactory 对象
     *
     * @param poolConfig
     * @return
     */
//    @Bean(name = "redisConnectionFactory")
//    public RedisConnectionFactory redisConnectionFactory(@Qualifier(value = "jedisPoolConfig") RedisConnection poolConfig) {
//        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
//        // 设置redis服务器的host和ip
//        redisStandaloneConfiguration.setHostName(this.host);
//        redisStandaloneConfiguration.setPort(this.port);
//        log.info("----> 初始化RedisConnectionFactory");
//        // 这里需要注意的是，edisConnectionFactoryJ对于Standalone模式的没有（RedisStandaloneConfiguration，JedisPoolConfig）的构造函数，
//        // 对此我们用JedisClientConfiguration接口的builder方法实例化一个构造器，还得类型转换
//        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcc = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
//        // 修改连接池配置
//        jpcc.poolConfig(poolConfig);
//        // 通过构造器来构造Jedis客户端配置
//        JedisClientConfiguration jedisClientConfiguration = jpcc.build();
//
//        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
//    }

    /**
     * 实例化 RedisTemplate 对象
     *
     * @return
     */
    @Bean(name = "myRedisTemplate")
    public RedisTemplate<String, Object> functionDomainRedisTemplate(@Qualifier(value = "lettuceConnectionFactory") LettuceConnectionFactory factory) {
        log.info("----> 初始化RedisTemplate...");
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new EntityRedisSerializer());
        redisTemplate.setHashValueSerializer(new EntityRedisSerializer());
        redisTemplate.afterPropertiesSet();
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }
}
